package com.up.vms.domain.vm.service;

import com.up.vms.domain.module.ActivityDTO;
import com.up.vms.domain.vm.entity.Activity;
import com.up.vms.domain.vm.enums.ActivityStatus;
import com.up.vms.domain.vm.repository.ActivityRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
public class ActivityService {

    @Autowired
    private ActivityRepository activityRepository;

    public Activity save(Activity activity) {
        Activity newOne = activityRepository.save(activity);
        return newOne;
    }

    public Activity getById(Long activityId) {
        Optional<Activity> optional = activityRepository.findById(activityId);

        if (optional.isPresent()) {
            return optional.get();
        } else {
            return null;
        }
    }

    public Activity getByName(String activityName) {
        List<Activity> list = activityRepository.findByActivityName(activityName);

        if (list != null && !list.isEmpty()) {
            return list.get(0);
        } else {
            return null;
        }
    }

    public Page<Activity> findAllByCase(ActivityDTO activityDTO) {


        Sort sort = new Sort(Sort.Direction.DESC, "created");
        Pageable pageable = PageRequest.of(activityDTO.getPage(), activityDTO.getSize(), sort);

        Specification<Activity> specification = new Specification<Activity>() {
            private static final long serialVersionUID = 1L;

            @Override
            public Predicate toPredicate(Root<Activity> root, CriteriaQuery<?> query,
                                         CriteriaBuilder criteriaBuilder) {
                List<Predicate> lst = new ArrayList<Predicate>();

                lst.add(criteriaBuilder.lessThan(root.get("status"), ActivityStatus.DELETED.code));

                if (activityDTO.getActivityName() != null) {
                    lst.add(criteriaBuilder.like(root.get("activityName"), "%" + activityDTO.getActivityName() + "%"));
                }

                if (activityDTO.getStartTime() != null) {
                    lst.add(criteriaBuilder.greaterThanOrEqualTo(root.get("endDate"), activityDTO.getStartTime()));
                }
                if (activityDTO.getEndTime() != null) {
                    lst.add(criteriaBuilder.lessThanOrEqualTo(root.get("startDate"), activityDTO.getEndTime()));
                }

                return query.where(lst.toArray(new Predicate[] {})).getRestriction();

            }
        };

        return activityRepository.findAll(specification, pageable);
    }
}
